#include <boot/multiboot.h>
#include <system/kernel.h>
#include <system/config.h>
#include <system/regs.h>
#include <system/syscall.h>
#include <system/term.h>
#include <system/mod.h>
#include <system/device.h>
#include <system/installer.h>
#include <system/debug.h>
#include <mmu/mmu.h>

#include <driver/fs/ramfs/ramfs.h>
#include <driver/fs/ext2/ext2.h>
#include <driver/hi/keyboard/keyboard.h>
#include <driver/hi/mouse/mouse.h>
#include <driver/rtc.h>
#include <driver/timer.h>
#include <driver/cpu.h>
#include <driver/video.h>
#include <driver/system/random/random.h>
#include <driver/system/null/null.h>
#include <driver/storage/ata_pio/ata_pio.h>
#include <driver/storage/floppy/floppy.h>
#include <driver/network/serial/serial.h>
#include <driver/network/ne2000/ne2000.h>
#include <driver/network/rtl8139/rtl8139.h>
#include <driver/graphics/vesa/vesa.h>

#include <fs/vfs.h>

#include <shell/shell.h>
#include <interrupt/gdt.h>
#include <interrupt/idt.h>
#include <interrupt/isr.h>
#include <interrupt/irq.h>
#include <task/task.h>
#include <task/tss.h>
#include <klibc/ctype.h>
#include <io.h>



/*
 * Spiderpig Logo
 */
void spiderpig_logo()
{
	video_set_attr(THEME_LOGO_COLOR);
	video_puts("   ____          _      _              ____   _              \n");
	video_puts("  / ___|  _ __  (_)  __| |  ___  _ __ |  _ \\ (_)  __ _      \n");
	video_puts("  \\___ \\ | '_ \\ | | / _` | / _ \\| '__|| |_) || | / _` |  \n");
	video_puts("   ___) || |_) || || (_| ||  __/| |   |  __/ | || (_| |      \n");
	video_puts("  |____/ | .__/ |_| \\__,_| \\___||_|   |_|    |_| \\__, |   \n");
	video_puts("         |_|                                     |___/       \n"); 
	video_set_attr(THEME_HEADER_COLOR);
	video_puts("  Spiderpig " SP_VERSION " compiled on " __DATE__ " at " __TIME__ "\n");	
}

/*
 *  Draw ok
 */
void spiderpig_put_state(int s)
{
	char x = video_get_attr();		
	video_gotoxy(VIDEO_COLS-5, video_get_y());
	video_puts(THEME_STATE_START);
	
	if(s == 0)
		video_color_puts(THEME_STATE_OK, "Ok");
	else if(s == 1)
		video_color_puts(THEME_STATE_ER, "!!");
	else if(s == 2)
		video_color_puts(THEME_STATE_WA, "!!");
		
	video_set_attr(x);
	video_puts(THEME_STATE_END);
	video_put('\n');
}

vfs_node_t *lol(char *name)
{
	vfs_node_t *dev = (vfs_node_t *) malloc(sizeof(vfs_node_t));
	strcpy(dev->name, name);
	printf("%s\n",dev->name);
	return dev;
}

/*
 *  Prima funzione che viene chiamata
 */
int spider_pig(multiboot_info_t *mboot_ptr)
{
	/*
	 * Visualizza un messaggio iniziale
	 */
	video_clear();
	if(THEME_IFLOGO) spiderpig_logo();	
	else
	{
		video_set_attr(THEME_HEADER_COLOR);
		video_puts("> Spiderpig " SP_VERSION " compiled on " __DATE__ " at " __TIME__ "\n\n");
	}
	video_set_attr(THEME_COLOR);

	debug_puts("spiderpig started.\n");


	/*
	 * Cpu initializing U_U
	 */
	//video_color_puts(THEME_START_COLOR, THEME_START_MSG);
	//video_puts("Setting up cpu info... (");
	cpu_init();
	//video_puts(CPU_VENDOR_NAME);
	//video_puts(")");
	//spiderpig_put_state(0);
	
	
	/*
	 * Starting descriptor tables
	 */
	video_color_puts(THEME_START_COLOR, THEME_START_MSG);
	video_puts("Setting up descriptor tables... ");
	gdt_install();
	//printf("(gdt, ");
	idt_install();
	//printf("idt, ");
	isrs_install();
	//printf("isr, ");
	irq_install();
	//printf("irq)");
	spiderpig_put_state(0);
	

	/*
	 * Inizializza la MMU
	 */
	video_color_puts(THEME_START_COLOR, THEME_START_MSG);
	video_puts("Setting up memory manager...");
	if(mmu_init(mboot_ptr->mem_lower, mboot_ptr->mem_upper)) return; //goto error;
	printf(" (%d MB of ram)",mmu_ram_size()/1024);
	spiderpig_put_state(0);


	mod_init();
	vfs_init();
	
	/*
	 * Registriamo tutti i moduli
	 */
	mod_add(&keyboard_module);
	mod_add(&mouse_module);
	mod_add(&serial_module);
	mod_add(&rtl8139_module);
	mod_add(&ne2000_module);
	mod_add(&floppy_module);
	mod_add(&null_module);
	mod_add(&random_module);
	mod_add(&vesa_module);
	mod_add(&ata_pio_module);
	mod_add(&video_module);
	mod_add(&ramfs_module);
	mod_add(&ext2_module);
	
	/*
	 * Inizializza gli handler degli irq fondamentali per l'os (timer, rtc, syscall e tastiera)
	 */
	//video_color_puts(THEME_START_COLOR, THEME_START_MSG);
	//video_puts("Initializing drivers... (");
	mod_initm(mod_get("video"), NULL);
	//printf("video, ");
	timer_init();
	//printf("timer, ");
	rtc_init();
	//printf("rtc, ");
	syscall_init();
	//printf("syscall, ");
	// In sardegna si dice 'amarolla'
	mod_initm(mod_get("keyboard"), NULL);
	//mod_initm(mod_get("null"), NULL);
	//printf("keyboard)");
	//spiderpig_put_state(0);
		
	//ata_pio_test();
	
	// Montiamo il tutto	
	video_color_puts(THEME_START_COLOR, THEME_START_MSG);
	video_puts("Mounting filesystems...");
	
	mod_initm(mod_get("ext2"), NULL);
	mod_initm(mod_get("ata_pio"), NULL);
	vfs_mount("devfs\0", 0, "/dev\0");
	vfs_mount("ext2\0", "/dev/hda\0", "/\0");
	
	vfs_root = vfs_get_mount_point("/\0");
	
	spiderpig_put_state(0);
	
	
	//vfs_node_t *dev = devfs_nodes;
	//while(dev != NULL){ printf("%s\n",dev->name); dev = dev->next; }
	/*
	 * Abilitiamo gli interrupt
	 */
	asm volatile("sti");
	//printf("%d\n",malloc(sizeof(vfs_node_t)));
	//char *a = (char *) malloc(sizeof(char)*VFS_NODE_NAME_LEN);
	//strcpy(a, "null");	
	//printf("\ndevfs %s\n",a);
	
	//while(1)
	//{
	//vfs_node_t *lola = lol("asd");
	//printf("%s %d\n",lola->name, lola);}
	
	//char asd[123];
	//vfs_get_node("/")->readdir(vfs_get_node("/"), asd, 0);
	//printf("%s\n\n",asd);
	//floppy_test();
	/*
	 * Stampiamo la data per far vedere che funziona sul serio
	 * l'rtc
	 */
	//video_color_puts(THEME_START_COLOR, THEME_START_MSG);
	//printf("Now is: ");
	//rtc_print_time();
	//printf("\n");
	

    /*
     * Inizializziamo il multitasking
     */
	video_color_puts(THEME_START_COLOR, THEME_START_MSG);
	video_puts("Setting up multitasking...");
	//task_init();
	spiderpig_put_state(0);   
	
	//task_exec("init", "init\0", NULL, NULL);
	//task_fork();
	//task_fork();
	//task_print_list();
	
	
	mod_uconfig();
	//installer();
	
	
	
	
    /*
     * Passiamo all'user mode
     */
	//video_color_puts(THEME_START_COLOR, THEME_START_MSG);
	//video_puts("Going on usermode...");
	//spiderpig_put_state(0);   
	//task_switch_to_user_mode();
	//while(1); 
	//putchar('\n');
    //syscall_call(SYSCALL_FS_FCLOSE, 0, 0, 0);
    //syscall_call(SYSCALL_DEBUG_OUT, (unsigned) 'l', 0, 0);
	//putchar('\n');
    //int x;
    //for(x = 0; x < 4; x++)
	//	printf("task_fork() pid: %d\n",task_fork());
	
	
	/*
	 * Start the shell
	 */
	video_color_puts(THEME_START_COLOR, THEME_START_MSG);
	video_puts("Starting built-in shell...");
	spiderpig_put_state(0);
	printf("\n");
	shell();
	
	while(1);
	
	
		
	/*
	 * Errore
	 */
	error:
		spiderpig_put_state(1);
		spiderpig_shutdown();
		
	return 0;
}


/*
 * Mostra le informazioni del multiboot header
 */
void spiderpig_show_multiboot_info(multiboot_info_t *mb)
{
	printf("Multiboot Info:\n");
	printf("\tFlags: %d\n",mb->flags);	
	printf("\tMem Lower: %d\n",mb->mem_lower);
	printf("\tMem Upper: %d\n",mb->mem_upper);
	//printf("\tBoot Device: %s\n",mb->boot_device);
	printf("\tKernel file: %s\n",mb->cmdline);
	printf("\tMods Count: %d\n",mb->mods_count);
	printf("\tMods Address: %d\n",mb->mods_addr);
	printf("\tMMap Lenght: %d\n",mb->mmap_length);
	printf("\tMMap Address: %d\n",mb->mmap_addr);
	printf("\tDrives Lenght: %d\n",mb->drives_length);
	printf("\tDrives Address: %d\n",mb->drives_addr);
	printf("\tConfig Table: %s\n",mb->config_table);
	printf("\tBoot Loader Name: %s\n",mb->boot_loader_name);
	//printf("\tApm Table: %s\n",mb->apm_table);
	printf("\tVBE Control Info: %d\n",mb->vbe_control_info);
	printf("\tVBE Mode info: %d\n",mb->vbe_mode_info);
	printf("\tVBE Mode: %d\n",mb->vbe_mode);
	printf("\tVBE Interface Seg: %d\n",mb->vbe_interface_seg);
	printf("\tVBE Interface Off: %d\n",mb->vbe_interface_off);
	printf("\tVBE Interface Len: %d\n",mb->vbe_interface_len);
}



/*
 * Deinizializza e spegne il pc
 */
void spiderpig_shutdown()
{
		asm("cli");
		asm("hlt");	
}



void spiderpig_reboot()
{    
	unsigned char good = 0x02;
	while ((good & 0x02) != 0)
		good = io_inb(0x64);
    io_outb(0x64, 0xFE);
}
